package com.example.process;

import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.converter.BpmnXMLConverter;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ProcessService {
    private static final String DEPLOY_NAME = "测试部署";
    @Resource
    private ProcessEngine engine;


    /**
     * 查询流程定义列表
     */
    List<Map<String, Object>> listProcessDefinition() {
        Deployment deployment = engine.getRepositoryService().createDeploymentQuery().deploymentKey(DEPLOY_NAME).latest().singleResult();
        if (ObjectUtils.isEmpty(deployment)) {
            return null;
        }
        List<ProcessDefinition> list = engine.getRepositoryService().createProcessDefinitionQuery()
                .deploymentId(deployment.getId())
                .latestVersion()
                .list();
        if (ObjectUtils.isEmpty(list)) {
            return null;
        }
        return list.stream()
                .map(s -> {
                    Map<String, Object> param = new HashMap<>(1);
                    param.put("deploymentId", s.getDeploymentId());
                    param.put("id", s.getId());
                    param.put("key", s.getKey());
                    param.put("name", s.getName());
                    param.put("tenantId", s.getTenantId());
                    param.put("version", s.getVersion());
                    param.put("category", s.getCategory());
                    return param;
                }).collect(Collectors.toList());
    }

    /**
     * 新建流程定义
     */
    void insertProcessDefinition() {
        List<FlowNode> flowNodeList = new ArrayList<>();
        // 创建节点定义
        createFlowNode(flowNodeList);
        // 创建节点连接
        List<SequenceFlow> sequenceFlowList = createSequenceFlowList(flowNodeList);
        // 新建流程定义
        Process process = createProcess(flowNodeList, sequenceFlowList);
        // 生成xml
        String xml = convertToXml(process);
        log.info("insertProcessDefinition - xml : {}", xml);
        // 部署
        Deployment deploy = deploy(process.getName(), xml);
        log.info("insertProcessDefinition - deploy id :{}", deploy.getId());
    }

    private Deployment deploy(String deployName, String xml) {
        return engine.getRepositoryService().createDeployment()
                .name(DEPLOY_NAME)
                .key(DEPLOY_NAME)
                .addString(deployName + ".bpmn20.xml", xml)
                .deploy();
    }

    private String convertToXml(Process process) {
        BpmnModel bpmnModel = new BpmnModel();
        bpmnModel.addProcess(process);
        BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
        byte[] bytes = bpmnXMLConverter.convertToXML(bpmnModel);
        return new String(bytes);
    }

    private Process createProcess(List<FlowNode> flowNodeList, List<SequenceFlow> sequenceFlowList) {
        Process process = new Process();
        process.setId(randomID());
        process.setName("测试自定义流程");
        // 将节点添加到流程中
        for (FlowNode flowNode : flowNodeList) {
            process.addFlowElement(flowNode);
        }
        // 将连线添加到流程中
        for (SequenceFlow sequenceFlow : sequenceFlowList) {
            process.addFlowElement(sequenceFlow);
        }
        return process;
    }

    private List<SequenceFlow> createSequenceFlowList(List<FlowNode> flowNodeList) {
        List<SequenceFlow> sequenceFlowList = new ArrayList<>();
        for (int i = 0; i < flowNodeList.size() - 1; i++) {
            FlowNode flowNode = flowNodeList.get(i);
            FlowNode flowNode1 = flowNodeList.get(i + 1);
            SequenceFlow sequenceFlow = new SequenceFlow(flowNode.getId(), flowNode1.getId());
            sequenceFlowList.add(sequenceFlow);
        }
        return sequenceFlowList;
    }

    private void createFlowNode(List<FlowNode> flowNodeList) {
        // 开始事件
        StartEvent startEvent = new StartEvent();
        startEvent.setId(randomID());
        startEvent.setName("开始节点");
        flowNodeList.add(startEvent);
        // 申请表单
        UserTask userTask1 = new UserTask();
        userTask1.setId(randomID());
        userTask1.setName("用户1审批");
        userTask1.setCandidateUsers(Collections.singletonList("user1"));
        flowNodeList.add(userTask1);
        // 审批节点
        UserTask userTask2 = new UserTask();
        userTask2.setId(randomID());
        userTask2.setName("用户2审批");
        userTask2.setCandidateUsers(Collections.singletonList("user2"));
        flowNodeList.add(userTask2);
        // 结束事件
        EndEvent endEvent = new EndEvent();
        endEvent.setId(randomID());
        endEvent.setName("结束节点");
        flowNodeList.add(endEvent);
    }

    private static String randomID() {
        return "sid-" + UUID.randomUUID().toString();
    }

    Map<String, Object> testStartProcessByIdAndUserId(String processDefinitionKey, String userId) {
        engine.getIdentityService().setAuthenticatedUserId(userId);
        ProcessInstance processInstance = engine.getRuntimeService().startProcessInstanceByKey(processDefinitionKey);
        Map<String, Object> result = new HashMap<>();
        result.put("id", processInstance.getId());
        result.put("processDefinitionId", processInstance.getProcessDefinitionId());
        result.put("processInstanceId", processInstance.getProcessInstanceId());
        return result;
    }

    void deleteAllProcess() {
        List<Deployment> list = engine.getRepositoryService().createDeploymentQuery().list();
        for (Deployment deployment : list) {
            engine.getRepositoryService().deleteDeployment(deployment.getId(), true);
        }
    }
}
